package com.hongyun.tms.infra.excel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hongyun.tms.common.constants.DefaultCreateByConstant;
import com.hongyun.tms.common.dto.dislog.DisLogImportDto;
import com.hongyun.tms.common.enums.BizCode;
import com.hongyun.tms.common.enums.DisLogEnum;
import com.hongyun.tms.common.utils.MapperingUtils;
import com.hongyun.tms.entity.TmsProdDisLog;
import com.hongyun.tms.exception.BusinessRuntimeException;
import com.hongyun.tms.service.TmsProdDisLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 调度日志导入
 *
 * @author liPeng
 * @date 2024-09-10
 */
@Slf4j
@Component
public class DisLogListener extends DefaultExcelListener<DisLogImportDto> {

    @Autowired
    private TmsProdDisLogService logService;

    public DisLogListener(TmsProdDisLogService logService) {
        this.logService = logService;
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("成功读取excel中【" + getRows().size() + "】条调度日志数据");

        // 获取读取的行数据
        List<DisLogImportDto> rows = getRows();

        // 创建一个 Set 用于检测 Excel 内部的重复数据
        Set<String> uniqueRecords = new HashSet<>();
        StringBuilder duplicateExcelRows = new StringBuilder();

        for (int i = 0; i < rows.size(); i++) {
            DisLogImportDto row = rows.get(i);
            String uniqueKey = row.getShiftDate() + "_" + row.getClassCode();

            // 检查 Excel 内部是否有重复
            if (uniqueRecords.contains(uniqueKey)) {
                duplicateExcelRows.append(String.format("第%d行: 日期 %s, 班次 %s 重复; ", i + 1, row.getShiftDate(), row.getClassCode()));
            } else {
                uniqueRecords.add(uniqueKey);
            }
        }

        // 如果发现Excel内部有重复，抛出异常
        if (duplicateExcelRows.length() > 0) {
            throw new BusinessRuntimeException(BizCode.EXCEL_ERROR, "Excel内部数据重复: " + duplicateExcelRows);
        }

        // 转为数据库实体对象列表
        List<TmsProdDisLog> reqDtoList = MapperingUtils.copyList(rows, TmsProdDisLog.class);

        // 校验数据库中的重复数据
        List<TmsProdDisLog> existingLogs = findByShiftDatesAndClassCodes(rows);
        StringBuilder duplicateDatabaseRows = new StringBuilder();

        for (int i = 0; i < rows.size(); i++) {
            DisLogImportDto row = rows.get(i);
            for (TmsProdDisLog existingLog : existingLogs) {
                if (existingLog.getShiftDate().equals(row.getShiftDate()) && existingLog.getClassCode().equals(row.getClassCode())) {
                    duplicateDatabaseRows.append(String.format("第%d行: 日期 %s, 班次 %s 已存在于数据库; ", i + 1, row.getShiftDate(), row.getClassCode()));
                    throw new BusinessRuntimeException(BizCode.EXCEL_ERROR,String.format("第%d行: 日期 %s, 班次 %s 已存在于数据库; ", i + 1, row.getShiftDate(), DisLogEnum.fromCode(row.getClassCode()).getDesc()));
                }
            }
        }

//        // 如果数据库中有重复数据，抛出异常
//        if (duplicateDatabaseRows.length() > 0) {
//            throw new BusinessRuntimeException(BizCode.EXCEL_ERROR, "数据库中存在重复数据: " + duplicateDatabaseRows);
//        }

        // 保存数据（可以进行批量插入）
        log.info("成功插入excel中【" + reqDtoList.size() + "】条调度日志数据");
        reqDtoList.forEach((log) -> {
            log.setCreateTime(LocalDateTime.now());
            log.setUpdateTime(LocalDateTime.now());
            log.setCreateBy(DefaultCreateByConstant.userId);
            log.setUpdateBy(DefaultCreateByConstant.userId);
            log.setCreateByName(DefaultCreateByConstant.userId.toString());
            log.setUpdateByName(DefaultCreateByConstant.userId.toString());
        });
        logService.saveBatch(reqDtoList);  // 批量保存
    }

    /**
     * 根据多个交接班日期和班次查询调度日志
     *
     * @param shiftDates 交接班日期列表
     * @param classCodes 班次列表
     * @return 调度日志列表
     */
    public List<TmsProdDisLog> findByShiftDatesAndClassCodes(List<DisLogImportDto> rows) {
        // 根据 shiftDate 和 classCode 执行批量查询，返回重复的数据
        List<LocalDate> shiftDates = rows.stream().map(DisLogImportDto::getShiftDate).collect(Collectors.toList());
        List<String> classCodes = rows.stream().map(DisLogImportDto::getClassCode).collect(Collectors.toList());

        LambdaQueryWrapper<TmsProdDisLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TmsProdDisLog::getShiftDate, shiftDates)
                .in(TmsProdDisLog::getClassCode, classCodes);

        return logService.list(queryWrapper);
    }

}
